/**
 * 载信软件(上海)有限公司
 * Copyright (c) 2015-2024 B5M,Inc.All Rights Reserved.
 */
package com.sys.midware.assist.reflection;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 反射工具类
 * <b>ClassName：</b> ReflectionTool <br/>
 * <b>Description：</b> TODO <br/>
 * <b>@author：</b> mobing <br/>
 * <b>@date：</b> 2016年4月28日 下午6:40:21 <br/>
 * <b>@version: </b>  <br/>
 */
public class ReflectionTool {

    private static Logger logger = LoggerFactory.getLogger(ReflectionTool.class);
    /**
     * 获取反射类的实例类型 
     * @param  
     * @return  Object
     */
    public static Object getInstanceOfClass(Class<?> clazz){
        try {
            return clazz.newInstance();
        }  catch (Exception e) {
            logger.error("getInstanceOfClass error!",e);            
        }
        return null;
    }
    
    /**
     * 判断原class和目标class是否有继承关系
     * exe.Ball.class.isAssignableFrom(FootBall.class)
     * @param  
     * @return  Object
     */
    public static boolean isAssignableFrom(Class<?> src,Class<?> dest){
        try {
            return src.isAssignableFrom(dest);
        }  catch (Exception e) {
            logger.error("isAssignableFrom error!",e);            
        }
        return false;
    }
    
    /**
     * 用来判断对象是否是类的实例
     * exe.FootBall.class.isInstance(new FootBall())
     * @param  
     * @return  Object
     */
    public static boolean isInstance(Class<?> src,Object obj){
        try {
            return src.isInstance(obj);
        }  catch (Exception e) {
            logger.error("isInstance error!",e);            
        }
        return false;
    }
    /**
     * 将类属性转换为Map<br>
     * <strong>注意：如果父类有同名字段，将被覆盖</strong>
     * @param  
     * @return  Map<String,Field>
     */
    public static Map<String, Field> convertClassToMap(Class<?> clz) {
        Map<String, Field> map = new HashMap<String, Field>();
        while (!Object.class.equals(clz)) {
            Field[] fields = clz.getDeclaredFields();
            for (Field f : fields) {
                if (Modifier.isStatic(f.getModifiers())) {
                    continue;
                }
                map.put(f.getName(), f);
            }
            clz = clz.getSuperclass();
        }
        return map;
    }
    
    /**
     * 根对象类型构造生成实例
     * 
     * @param clz
     *            对象类型
     * @return
     */
    public static <T> T create(Class<T> clz) {
        try {
            T obj = clz.getConstructor(new Class[0]).newInstance(new Object[0]);
            return obj;
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage(), e);
        }
    }
    /**
     * 将map转换成指定对象类型的实例
     * 
     * @param clazz
     *            对象类型
     * @param map
     * @return
     */
    public static <T> T convertMapToObject(Map<?, ?> map,Class<T> clazz) {
        T obj = create(clazz);
        Class<?> clz = clazz;
        while (!Object.class.equals(clz)) {
            Field[] fields = clz.getDeclaredFields();
            for (Field f : fields) {
                int modifier = f.getModifiers();
                if (!Modifier.isFinal(modifier) || Modifier.isStatic(modifier)) {
                    f.setAccessible(true);
                    String name = f.getName();
                    Object value = map.get(name);
                    try {
                        f.set(obj, value);
                    } catch (Exception e) {
                    }
                }
            }
            clz = clz.getSuperclass();
        }

        return obj;
    }
    /**
     * 判断两个类是否相等
     * @param  
     * @return  boolean
     */
    public static boolean equals(Class<?> a, Class<?> b) {
        return a == b;
    }
    /**
     * 实现基本数据类型、日期类型、封装类型间的智能转换
     * 
     * @param target
     *            转换类型
     * @param srcValue
     *            原始数据
     * @return
     */
    @SuppressWarnings({ "unchecked", "rawtypes" })
    public static <T> T convertType(Class<T> target, Object srcValue) {
        if (srcValue == null) {
            return null;
        }
        if (target == null) {
            throw new NullPointerException();
        }
        Class<?> src = srcValue.getClass();
        if (target.equals(src)) {
            return (T) srcValue;
        }

        Object obj;
        try {
            if (equals(target, boolean.class) || equals(target, Boolean.class)) {
                obj = Boolean.parseBoolean(srcValue.toString());
            } else if (equals(target, byte.class) || equals(target, Byte.class)) {
                obj = Byte.parseByte(srcValue.toString());
            } else if (equals(target, short.class) || equals(target, Short.class)) {
                obj = Short.parseShort(srcValue.toString());
            } else if (equals(target, int.class) || equals(target, Integer.class)) {
                obj = Integer.parseInt(srcValue.toString());
            } else if (equals(target, long.class) || equals(target, Long.class)) {
                obj = Long.parseLong(srcValue.toString());
            } else if (equals(target, float.class) || equals(target, Float.class)) {
                obj = Float.parseFloat(srcValue.toString());
            } else if (equals(target, double.class) || equals(target, Double.class)) {
                obj = Double.parseDouble(srcValue.toString());
            } else if (equals(target, char.class) || equals(target, Character.class)) {
                obj = srcValue.toString().charAt(0);
            } else if (equals(target, Date.class)) {
                if (srcValue instanceof Long) {
                    obj = new Date((Long) srcValue);
                } else {
                    String str = srcValue.toString();
                    try {
                        long val = Long.parseLong(str);
                        obj = new Date(val);
                    } catch (RuntimeException e) {
                        try {
                            obj = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(str);
                        } catch (ParseException e1) {
                            throw new RuntimeException(e1);
                        }
                    }
                }
            } else if (target.isEnum()) {
                obj = Enum.valueOf((Class<Enum>) target, srcValue.toString());
            } else if (equals(target, String.class)) {
                obj = srcValue.toString();
            } else {
                throw new RuntimeException(target + "不支持自动转换");
            }
            return (T) obj;
        } catch (Exception e) {
//            throw convertReflectionExceptionToUnchecked(e);
        }
        return null;
    }
    
   
   

    /**
     * 通过反射给指定类实例字段注入数据<br>
     * 数据类型将会自动实现转换<br>
     * 如果字段类型为日期类型，会自动将"yyyy-MM-dd HH:mm:ss"格式的字符串转换为日期类型
     * 
     * @param target
     *            类实例
     * @param field
     *            对应字段
     * @param value
     *            字段数值
     */
    @SuppressWarnings({ "unchecked", "rawtypes" })
    public static void setFieldValueAuto(Object target, Field field, Object value) {
        if (value == null) {
            return;
        }
        Class<?> clz = field.getType();
        try {
            if (equals(clz, boolean.class)) {
                if (value instanceof Boolean) {
                    field.setBoolean(target, (Boolean) value);
                } else {
                    field.setBoolean(target, Boolean.parseBoolean(value.toString()));
                }
            } else if (equals(clz, byte.class)) {
                if (value instanceof Byte) {
                    field.setByte(target, (Byte) value);
                } else {
                    field.setByte(target, Byte.parseByte(value.toString()));
                }
            } else if (equals(clz, short.class)) {
                if (value instanceof Short) {
                    field.setShort(target, (Short) value);
                } else {
                    field.setShort(target, Short.parseShort(value.toString()));
                }
            } else if (equals(clz, int.class)) {
                if (value instanceof Integer) {
                    field.setInt(target, (Integer) value);
                } else {
                    field.setInt(target, Integer.parseInt(value.toString()));
                }
            } else if (equals(clz, long.class)) {
                if (value instanceof Long) {
                    field.setLong(target, (Long) value);
                } else {
                    field.setLong(target, Long.parseLong(value.toString()));
                }
            } else if (equals(clz, float.class)) {
                if (value instanceof Float) {
                    field.setFloat(target, (Float) value);
                } else {
                    field.setFloat(target, Float.parseFloat(value.toString()));
                }
            } else if (equals(clz, double.class)) {
                if (value instanceof Double) {
                    field.setDouble(target, (Double) value);
                } else {
                    field.setDouble(target, Double.parseDouble(value.toString()));
                }
            } else if (equals(clz, char.class)) {
                if (value instanceof Character) {
                    field.setChar(target, (Character) value);
                } else {
                    field.setChar(target, value.toString().charAt(0));
                }
            } else if (equals(clz, Boolean.class)) {
                if (value instanceof Boolean) {
                    field.set(target, (Boolean) value);
                } else {
                    field.set(target, Boolean.valueOf(value.toString()));
                }
            } else if (equals(clz, Byte.class)) {
                if (value instanceof Byte) {
                    field.set(target, (Byte) value);
                } else {
                    field.set(target, Byte.valueOf(value.toString()));
                }
            } else if (equals(clz, Short.class)) {
                if (value instanceof Short) {
                    field.set(target, (Short) value);
                } else {
                    field.set(target, Short.valueOf(value.toString()));
                }
            } else if (equals(clz, Integer.class)) {
                if (value instanceof Integer) {
                    field.set(target, (Integer) value);
                } else {
                    field.set(target, Integer.valueOf(value.toString()));
                }
            } else if (equals(clz, Long.class)) {
                if (value instanceof Long) {
                    field.set(target, (Long) value);
                } else {
                    field.set(target, Long.valueOf(value.toString()));
                }
            } else if (equals(clz, Float.class)) {
                if (value instanceof Float) {
                    field.set(target, (Float) value);
                } else {
                    field.set(target, Float.valueOf(value.toString()));
                }
            } else if (equals(clz, Double.class)) {
                if (value instanceof Double) {
                    field.set(target, (Double) value);
                } else {
                    field.set(target, Double.valueOf(value.toString()));
                }
            } else if (equals(clz, Character.class)) {
                if (value instanceof Character) {
                    field.set(target, (Character) value);
                } else {
                    field.set(target, value.toString().charAt(0));
                }
            } else if (equals(clz, Date.class)) {
                if (value instanceof Date) {
                    field.set(target, (Date) value);
                } else if (value instanceof Long) {
                    field.set(target, new Date((Long) value));
                } else {
                    String str = value.toString();
                    try {
                        long val = Long.parseLong(str);
                        field.set(target, new Date(val));
                    } catch (RuntimeException e) {
                        try {
                            field.set(target, new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(str));
                        } catch (ParseException e1) {
                            throw new RuntimeException(e);
                        }
                    }
                }
            } else if (clz.isEnum()) {
                field.set(target, Enum.valueOf((Class<Enum>) clz, value.toString()));
            } else {
                field.set(target, value);
            }
        } catch (Exception e) {
            
//            throw convertReflectionExceptionToUnchecked(e);
        }
    }

    

    /**
     * 给指定实例注入字段数据,类型自动转换
     * 
     * @param obj
     *            类实例
     * @param field
     *            字段名称
     * @param value
     *            字段数值
     */
    public static void setFieldValue(Object obj, String field, Object value) {
        Class<?> p = obj.getClass();
        while (!Object.class.equals(p)) {
            try {
                Field f = p.getDeclaredField(field);
                f.setAccessible(true);
                f.set(obj, value);
            } catch (Exception e) {
                // throw new RuntimeException(e);
            }
            p = p.getSuperclass();
        }
    }

    
   

    /**
     * 获取对应字段的数值
     * 
     * @param obj
     *            类实例
     * @param field
     *            字段名称
     * @return
     */
    @SuppressWarnings("unchecked")
    public static <T> T getFieldValue(Object obj, String field) {
        Class<?> clz = obj.getClass();
        while (!Object.class.equals(clz)) {
            try {
                Field f = clz.getDeclaredField(field);
                if (f != null) {
                    f.setAccessible(true);
                    Object value = f.get(obj);
                    return (T) value;
                }
            } catch (Exception e) {
                // e.printStackTrace();
            }
            clz = clz.getSuperclass();
        }
        return null;
    }


    /**
     * 通过给定的正则式，调用指定对象中名称匹配的公有无参方法，且不包括静态方法
     * 
     * @param obj
     * @param methodRegex
     */
    public static <T> void invokeMethod(T obj, String methodRegex) {
        if (obj == null) {
            return;
        }
        Class<?> clz = obj.getClass();
        do {
            Method[] methods = clz.getDeclaredMethods();
            for (Method method : methods) {
                int modifier = method.getModifiers();
                if (Modifier.isStatic(modifier) || !Modifier.isPublic(modifier)) {
                    continue;
                }
                if (!method.getName().matches(methodRegex)) {
                    continue;
                }
                int len = method.getParameterTypes().length;
                if (len < 1) {
                    try {
                        method.invoke(obj, new Object[0]);
                    } catch (Exception e) {
                        // e.printStackTrace();
                    }
                }
            }
            clz = clz.getSuperclass();
        } while (!Object.class.equals(clz));
    }


    /**
     * 通过反射调实例的方法
     * 
     * @param obj
     *            对象实例
     * @param methodName
     *            方法名
     * @param argTypes
     *            方法参数类型
     * @param args
     *            方法参数
     * @return
     * @throws SecurityException
     * @throws IllegalArgumentException
     * @throws NoSuchMethodException
     * @throws IllegalAccessException
     * @throws InvocationTargetException
     */
    @SuppressWarnings("unchecked")
    public static <T> T invokeMethod(Object obj, String methodName, Class<?>[] argTypes, Object[] args)
            throws SecurityException, IllegalArgumentException, NoSuchMethodException, IllegalAccessException,
            InvocationTargetException {
        Class<?> clazz = obj.getClass();
        Method method = null;
        if(argTypes !=null && argTypes.length >0){ //调用有参方法
            method = clazz.getMethod(methodName, argTypes);
            method.setAccessible(true);
            return (T) method.invoke(obj, args);
        }else {//调用无参方法
            method = clazz.getMethod(methodName);
            method.setAccessible(true);
            return (T) method.invoke(obj);
        }
        
    }


}
